/*
	This file is part of PropExtractor.

	PropExtractor is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	PropExtractor is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with PropExtractor. If not, see <http://www.gnu.org/licenses/>.
*/

#include "PEIncludes.h"

#include "PETools.h"

namespace pe
{

	// ================================
	// Tools
	// ================================

	int CheckDirectory(const wchar_t* a_FilePath)
	{
		wchar_t* lastslash = wcsrchr((wchar_t*)a_FilePath, L'\\');
		if (!lastslash) 
		{
			lastslash = wcsrchr((wchar_t*)a_FilePath, L'/');
		}
		if (!lastslash) 
		{ 
			return -1; 
		}

		wchar_t filedir[_MAX_PATH] = { 0 };
		wcsncat(filedir, a_FilePath, lastslash - a_FilePath + 1);

		//PE_DEBUG("File directory: %s", filedir);

		// NOTE: for any cross platform dudes out there, this will be probably need to be fixed
		int success = SHCreateDirectoryExW(NULL, filedir, NULL);
		if (success != 0 && success != ERROR_ALREADY_EXISTS)
		{
			PE_PRINT("ERROR! Could not create directory. Try adding the working directory.");
			return -1;
		}

		return PE_OK;
	}

	int GetPatternedPath(wchar_t* a_Target, size_t* a_Length, const char* a_Pattern, const wchar_t* a_Path, const wchar_t* a_WorkingDir, unsigned int a_Index)
	{
		memset(a_Target, 0, _MAX_PATH);

		unsigned int dir_length = 0;
		wchar_t* lastslash = wcsrchr((wchar_t*)a_Path, L'\\');
		if (!lastslash) 
		{ 
			lastslash = wcsrchr((wchar_t*)a_Path, L'/'); 
		}

		if (!lastslash) 
		{ 
			lastslash = (wchar_t*)a_Path; 
			dir_length = wcslen(a_Path);
		}
		else
		{
			lastslash++;
			dir_length = lastslash - a_Path;
		}

		unsigned int filename_length = 0;
		wchar_t* lastdot = wcsrchr((wchar_t*)a_Path, L'.');
		if (!lastdot)
		{
			// BUGFIX: i instead of . in file?
			lastdot = wcsrchr((wchar_t*)a_Path, (wchar_t)0x69);
		}

		if (lastdot)
		{
			filename_length = lastdot - lastslash;
		}
		else
		{
			filename_length = wcslen(lastslash + 1) + 1;
		}
		wchar_t* filename = new wchar_t[filename_length + 1];
		memset(filename, 0, (filename_length + 1) * 2);
		wcsncat(filename, lastslash, filename_length);

		char command[256];
		const char* src = a_Pattern;
		char* dst = command;
		bool add = false;

		wchar_t workingdir[_MAX_PATH];
		if (!a_WorkingDir)
		{
			wchar_t dir[_MAX_PATH];
			GetModuleFileNameW(NULL, dir, _MAX_PATH);
			wchar_t* lastslash = wcsrchr(dir, '\\');
			wcsncpy(workingdir, dir, lastslash - dir + 1);
			workingdir[lastslash - dir + 1] = 0;

			/*char* lastslash = strrchr((char*)a_Path, '\\');
			if (!lastslash)
			{
				lastslash = strrchr((char*)a_Path, '/');
			}

			strncpy(workingdir, a_Path, lastslash - a_Path + 1);
			workingdir[lastslash - a_Path + 1] = 0;*/
		}
		else
		{
			wcscpy(workingdir, a_WorkingDir);
		}

		for (size_t i = 0; i < strlen(a_Pattern); i++)
		{
			if (*src == '%')
			{
				if (add)
				{
					*dst++ = 0;
					if (!strcmp(command, "workingdir"))
					{
						wcscat(a_Target, workingdir);
					}
					else if (!strcmp(command, "dir"))
					{
						wcsncat(a_Target, a_Path, lastslash - a_Path);
					}
					else if (!strcmp(command, "name"))
					{
						wcscat(a_Target, filename);
					}
					else if (!strcmp(command, "ext"))
					{
						wcscat(a_Target, lastdot);
					}
					else if (!strcmp(command, "index"))
					{
						char number[256];
						_itoa(a_Index, number, 10);

						wchar_t* str;
						PE_STRTOWIDE(str, number);
						wcscat(a_Target, str);
						delete str;
					}

					dst = command;
					add = false;
				}
				else
				{
					add = true;
				}

				src++;
				continue;
			}

			if (add)
			{
				*dst++ = *src;
			}
			else
			{
				unsigned int len = 1;
				wchar_t* str = new wchar_t[len + 1];
				memset(str, 0, (len + 1) * 2);
				mbtowc(str, src, len);
				wcscat(a_Target, str);
				delete str;
			}
			src++;
		}

		*a_Length = wcslen(a_Target);

		return 0;
	}

	int WriteTGA(const char* a_FilePath, unsigned int a_Width, unsigned int a_Height, byte* a_Data)
	{
		FILE* handle = fopen(a_FilePath, "w+b");
		if (!handle) { return -1; }

		byte id = 0;			                fwrite(&id, 1, 1, handle);
		byte colormap = 0;		                fwrite(&colormap, 1, 1, handle);
		byte compression = 2;                   fwrite(&compression, 1, 1, handle);

		word colormap_offset = 0;               fwrite(&colormap_offset, 1, 1, handle);
		word colormap_length = 0;               fwrite(&colormap_length, 1, 1, handle);
		byte colormap_bpp = 0;                  fwrite(&colormap_bpp, 1, 1, handle);

		word padding = 0;                       fwrite(&padding, 2, 1, handle);

		word origin_x = 0;                      fwrite(&origin_x, 2, 1, handle);
		word origin_y = 0;                      fwrite(&origin_y, 2, 1, handle);

		word width = (word)a_Width;             fwrite(&width, 2, 1, handle);
		word height = (word)a_Height;           fwrite(&height, 2, 1, handle);

		byte depth = 24;                        fwrite(&depth, 1, 1, handle);

		byte img_descriptor = 0;                fwrite(&img_descriptor, 1, 1, handle);

		// write to the file

		for (unsigned int y = a_Height; y > 0; y--)
		{
			byte* data = a_Data + ((y - 1) * a_Width * 3);
			fwrite(data, 3, a_Width, handle);
		}

		fclose(handle);

		//ShellExecuteA(NULL, NULL, a_FilePath, NULL, NULL, SW_SHOW);

		return 0;
	}

	int ReadBytes(void* a_Target, unsigned int a_ElementSize, unsigned int a_Amount, byte* a_Source)
	{
		byte* dst = (byte*)a_Target;
		byte* src = a_Source;

		for (unsigned int i = 0; i < a_Amount; i++)
		{
			for (unsigned int j = 0; j < a_ElementSize; j++)
			{
				dst[j] = src[j];
			}

			dst += a_ElementSize;
			src += a_ElementSize;
		}

		return a_ElementSize * a_Amount;
	}

	int ReadUTF8String(wchar_t** a_Target, byte* a_Source)
	{
		char str[256] = { 0 };
		char* dst = str;
		byte* src = a_Source;
		char c;

		do
		{
			ReadBytes(&c, 1, 1, src++);
			*dst++ = c;
		} 
		while (c != 0);

		size_t in_len = strlen((char*)a_Source);

		/**a_Target = new char[strlen(str) + 1];
		memset(*a_Target, 0, strlen(str) + 1);
		strcpy(*a_Target, str);*/

		*a_Target = new wchar_t[in_len + 1];
		memset(*a_Target, 0, (in_len + 1) * sizeof(wchar_t));
		MultiByteToWideChar(
			932, 
			0, 
			str, 
			strlen(str), 
			*a_Target, 
			in_len
		);

		return (in_len + 1);
	}

	int StripSpecialCharsAndSave(char** a_Target, char* a_Source)
	{
		*a_Target = new char[strlen(a_Source) + 1];
		memset(*a_Target, 0, strlen(a_Source) + 1);

		char* dst = *a_Target;
		char* src = a_Source;
		do
		{
			if (*src & 0x80)
			{
				*dst = '?';
			}
			else if (*src == ' ')
			{
				*dst = '_';
			}
			else
			{
				*dst = *src;
			}

			dst++;
			src++;
		}
		while (*src != 0);

		return 0;
	}

}